package com.hanock.sm.fork2d;


import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.graphics.RectF;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;
import android.os.SystemClock;
import android.util.Log;

public class Fork2dRenderer implements Renderer {
	
	private static final float VIEWPORT_RATIO = 1280/720.0f;
	
	// fps related variables
	private int drawCount;
	private long startTime;
	
	private RectF tempRectF;
	
	private ViewportInfo viewportInfo;
	
	// core
	private Canvas canvas;
	private Fork2dContext fork2dContext;
	private TextureManager textureManager;
	
	
	public Fork2dRenderer(Fork2dContext fork2dContext) {
		
		this.fork2dContext = fork2dContext;
		this.textureManager = TextureManager.getInstance();
		
		tempRectF = new RectF();
		canvas = new Canvas();
		
		viewportInfo = new ViewportInfo();
	}
	
	@Override
	public final void onDrawFrame(GL10 gl) {
		
		//
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
		
		
		//
		Scene curScene = SceneManager.getInstance().getCurrentScene();
		
		if (curScene == null)
			return;
		
		
		//
		viewportInfo.sceneWidth = curScene.getWidth();
		viewportInfo.sceneHeight = curScene.getHeight();
		canvas.beforeDraw(gl, viewportInfo);
		
		
		// ----------------------------------------------------------------
		// critical section 
		
		if (curScene != null){
			Object sync = fork2dContext.getMonitor();
			
			curScene.getDesRect(tempRectF);
			gl.glMatrixMode(GL10.GL_PROJECTION);  
		    gl.glLoadIdentity();
		    GLU.gluOrtho2D(gl, tempRectF.left, tempRectF.right, tempRectF.bottom, tempRectF.top);

		    if (curScene.isDirty()){
		    	textureManager.releaseDisposables();
		    	curScene.refresh();
		    	curScene.setDirty(false);
		    }
		    
			synchronized (sync) {
				curScene.visit(canvas);
			}
		}
		// ----------------------------------------------------------------
		
		
		//
		canvas.afterDraw();
		
		
		// ------- fps -------
		drawCount++;
		if (startTime == 0){
			startTime = SystemClock.elapsedRealtime();
			drawCount = 0;
		}
		else {
			long curTime = SystemClock.elapsedRealtime();
			if (curTime >= startTime + 5000){
				Log.i("test", "fps: " + drawCount/5f);
				drawCount = 0;
				startTime = curTime;
			}
		}
	}

	@Override
	public final void onSurfaceChanged(GL10 gl, int width, int height) {
		
		float surfaceRatio = 1f*width/height;
		
		int viewportWidth = 0;
		int viewportHeight = 0;
		
		if (VIEWPORT_RATIO > surfaceRatio){			
			viewportWidth = width;
			viewportHeight = (int)(viewportWidth/VIEWPORT_RATIO);
		}
		else{
			viewportHeight = height;
			viewportWidth = (int)(viewportHeight*VIEWPORT_RATIO);
		}
		
		int cx = width/2;
		int cy = height/2;
		
		int left = cx - (int)viewportWidth/2;
		int bottom = cy - (int)viewportHeight/2;
		
		gl.glViewport(left, bottom, viewportWidth, viewportHeight);
		
		viewportInfo.left = left;
		viewportInfo.bottom = bottom;
		viewportInfo.surfaceWidth = width;
		viewportInfo.surfaceHeight = height;
		viewportInfo.width = viewportWidth;
		viewportInfo.height = viewportHeight;
	}

	@Override
	public final void onSurfaceCreated(GL10 gl, EGLConfig config) {
		
		//
		textureManager.onSurfaceCreated(gl);
		
		//
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glEnable(GL10.GL_DEPTH_TEST); 
		gl.glEnable(GL10.GL_BLEND);
		
		gl.glDisable(GL10.GL_COLOR_MATERIAL);
		
		gl.glShadeModel(GL10.GL_SMOOTH);
		gl.glClearColor(0, 0, 0, 1);
		gl.glClearDepthf(1.0f); 
		gl.glDepthFunc(GL10.GL_LEQUAL);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
	}
	
	
	
	// ----------------------------------------------------------------------
	// Options
	// ----------------------------------------------------------------------
		
	// ----------------------------------------------------------------------
	// Getters & Setters
	// ----------------------------------------------------------------------
	
	public ViewportInfo getViewportInfo() {
		return viewportInfo;
	}
}















